﻿//-----------------------------------------------------------------------
// <copyright file="CharacterClass.cs" company="FastNET Services">
//     Copyright (c) 2008-2009. All Rights Reserved.
// </copyright>
// <license>
//     GPLv2
// </license>
// <warranty>
//     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
//     BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
//     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
//     DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//     OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// </warranty>
//-----------------------------------------------------------------------
#region Usings

using System;
using System.Collections.Generic;
using GateShift.Common.Repository;
using GateShift.Common.Repository.Business;
using GateShift.Common.Repository.Interfaces.DataInterfaces;
using GateShift.Common.Repository.Interfaces.Factories;
using GateShift.Common.Repository.Interfaces.Repositories;

#endregion

namespace GateShift.Services.GameFramework.GameObjects
{
    /// <summary>
    /// Business class for managing all character and class mapping related activity
    /// </summary>
    public class CharacterClass : BusinessBase<ICharacterClassData, ICharacterClassRepository>
    {
        #region Fields

        private Class _class; // DO NOT reference unless setting to null. Use the property that is lazy loaded
        private Character _character; // DO NOT reference unless setting to null. Use the property that is lazy loaded

        #endregion

        #region CTor/DTor

        #region Creation Routines

        /// <summary>
        /// Initializes a new instance of the CharacterClass class
        /// </summary>
        public CharacterClass()
            : this(new RepositoryFactory())
        {
        }

        /// <summary>
        /// Initializes a new instance of the CharacterClass class
        /// </summary>
        /// <param name="factory">Factory for retrieving the Repository from</param>
        /// <exception cref="ArgumentNullException">Thrown if Factory is null</exception>
        public CharacterClass(IRepositoryFactory factory)
            : base(factory)
        {
        }

        #endregion

        #region Retrieve by IDs

        /// <summary>
        /// Initializes a new instance of the CharacterClass class
        /// </summary>
        /// <param name="characterID">Identity of the character part of the map to retrieve</param>
        /// <param name="classID">Identity of the class part of the map to retrieve</param>
        /// <exception cref="ArgumentNullException">Thrown if characterID or classID are null</exception>
        public CharacterClass(Identity characterID, Identity classID)
            : this(new RepositoryFactory(), characterID, classID)
        {
        }

        /// <summary>
        /// Initializes a new instance of the CharacterClass class
        /// </summary>
        /// <param name="factory">Factory for retrieving the Repository from</param>
        /// <param name="characterID">Identity of the character part of the map to retrieve</param>
        /// <param name="classID">Identity of the class part of the map to retrieve</param>
        /// <exception cref="ArgumentNullException">Thrown if factory is null</exception>
        public CharacterClass(IRepositoryFactory factory, Identity characterID, Identity classID)
            : base(factory)
        {
            if (factory == null)
            {
                throw new ArgumentNullException("factory", "Cannot retrieve data without a factory");
            }

            Repository = RetrieveRepository(factory);
            Data = Repository.Retrieve(characterID, classID);
            Factory = factory;

            if (Data == null)
            {
                throw new InvalidOperationException(string.Format("Unable to retrieve data from database with characterID of {0} and classID of {1}", characterID, classID));
            }
        }

        #endregion

        #region Retrieve by Data

        /// <summary>
        /// Initializes a new instance of the CharacterClass class
        /// </summary>
        /// <param name="factory">Factory for retrieving the Repository from</param>
        /// <param name="data">ICharacterClassData of the data to retrieve</param>
        /// <exception cref="ArgumentNullException">Thrown if Factory or ID are null</exception>
        private CharacterClass(IRepositoryFactory factory, ICharacterClassData data)
            : base(factory, data)
        {
        }

        #endregion

        #endregion

        #region Lazy Loaded Properties

        /// <summary>
        /// Gets the character associated with this CharacterClass
        /// </summary>
        public Character Character
        {
            get
            {
                if (_character == null)
                {
                    _character = new Character(Factory, Data.CharacterID);
                }

                return _character;
            }
        }

        /// <summary>
        /// Gets the class associated with this CharacterClass
        /// </summary>
        public Class Class
        {
            get
            {
                if (_class == null)
                {
                    _class = new Class(Factory, Data.ClassID);
                }

                return _class;
            }
        }

        #endregion

        #region Data Properties

        /// <summary>
        /// Gets or sets the number of ranks this mapping has
        /// </summary>
        public byte Ranks
        {
            get
            {
                return Data.Ranks;
            }

            set
            {
                Data.Ranks = value;
            }
        }

        /// <summary>
        /// Gets or sets the Character Identity associated with this mapping
        /// </summary>
        public Identity CharacterID
        {
            get
            {
                return Data.CharacterID;
            }

            set
            {
                Data.CharacterID = value;
                _character = null;
            }
        }

        /// <summary>
        /// Gets or sets the Class Identity associated with this mapping
        /// </summary>
        public Identity ClassID
        {
            get
            {
                return Data.ClassID;
            }

            set
            {
                Data.ClassID = value;
                _class = null;
            }
        }

        #endregion

        #region Calculated Attributes

        /// <summary>
        /// Gets the character's class total Accuracy
        /// </summary>
        public short TotalAccuracy
        {
            get
            {
                return (short)((Class == null) ? 0 : Ranks * Class.TotalAccuracy);
            }
        }

        /// <summary>
        /// Gets the character's class total Agility
        /// </summary>
        public short TotalAgility
        {
            get
            {
                return (short)((Class == null) ? 0 : Ranks * Class.TotalAgility);
            }
        }

        /// <summary>
        /// Gets the character's class total Endurance
        /// </summary>
        public short TotalEndurance
        {
            get
            {
                return (short)((Class == null) ? 0 : Ranks * Class.TotalEndurance);
            }
        }

        /// <summary>
        /// Gets the character's class total Energy
        /// </summary>
        public short TotalEnergy
        {
            get
            {
                return (short)((Class == null) ? 0 : Ranks * Class.TotalEnergy);
            }
        }

        /// <summary>
        /// Gets the character's class total Force
        /// </summary>
        public short TotalForce
        {
            get
            {
                return (short)((Class == null) ? 0 : Ranks * Class.TotalForce);
            }
        }

        /// <summary>
        /// Gets the character's class total Insight
        /// </summary>
        public short TotalInsight
        {
            get
            {
                return (short)((Class == null) ? 0 : Ranks * Class.TotalInsight);
            }
        }

        /// <summary>
        /// Gets the character's class total Intellect
        /// </summary>
        public short TotalIntellect
        {
            get
            {
                return (short)((Class == null) ? 0 : Ranks * Class.TotalIntellect);
            }
        }

        /// <summary>
        /// Gets the character's class total Strength
        /// </summary>
        public short TotalStrength
        {
            get
            {
                return (short)((Class == null) ? 0 : Ranks * Class.TotalStrength);
            }
        }

        /// <summary>
        /// Gets the character's class total Will
        /// </summary>
        public short TotalWill
        {
            get
            {
                return (short)((Class == null) ? 0 : Ranks * Class.TotalWill);
            }
        }

        #endregion

        #region Public Static Factory Methods

        /// <summary>
        /// Retrieves the CharacterClasses for the requested Character Identity
        /// </summary>
        /// <param name="characterID">The Identity of the Character to retrieve CharacterClasses for</param>
        /// <returns>List of CharacterClass of all matching results</returns>
        /// <exception cref="ArgumentNullException">Thrown if characterID is null</exception>
        public static List<CharacterClass> RetrieveCharacterClasses(Identity characterID)
        {
            return RetrieveCharacterClasses(new RepositoryFactory(), characterID);
        }

        #endregion

        #region Public Validations

        /// <summary>
        /// Validates the CharacterClass is valid
        /// </summary>
        /// <returns>Boolean based on the validity of the object</returns>
        public override bool IsValid()
        {
            // TODO : Other values

            // Everything passed by this point!
            return true;
        }

        #endregion

        #region Internal Static Factory Methods

        /// <summary>
        /// Retrieves the CharacterClasses for the requested Character Identity
        /// </summary>
        /// <param name="factory">Factory for retrieving the CharacterClasses from</param>
        /// <param name="characterID">The Identity of the Character to retrieve CharacterClasses for</param>
        /// <returns>List of CharacterClass of all matching results</returns>
        /// <exception cref="ArgumentNullException">Thrown if either factory or characterID are null</exception>
        internal static List<CharacterClass> RetrieveCharacterClasses(IRepositoryFactory factory, Identity characterID)
        {
            if (factory == null)
            {
                throw new ArgumentNullException("factory", "Factory cannot be null to retrieve from");
            }

            List<CharacterClass> returnValue = new List<CharacterClass>();

            IList<ICharacterClassData> results = factory.GetRepository<ICharacterClassRepository>().Retrieve(characterID);

            if (results != null)
            {
                foreach (ICharacterClassData characterClass in results)
                {
                    returnValue.Add(new CharacterClass(factory, characterClass));
                }
            }

            return returnValue;
        }

        #endregion
    }
}